package com.cicadasmall.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cicadasmall.common.base.BaseService;
import com.cicadasmall.common.constant.Constant;
import com.cicadasmall.common.exception.ServiceException;
import com.cicadasmall.common.func.Fn;
import com.cicadasmall.common.resp.R;
import com.cicadasmall.system.dto.DeptInputDTO;
import com.cicadasmall.system.dto.DeptQueryDTO;
import com.cicadasmall.system.dto.DeptUpdateDTO;
import com.cicadasmall.data.domain.DeptDO;
import com.cicadasmall.system.service.IDeptService;
import com.cicadasmall.system.vo.DeptVO;
import com.cicadasmall.data.mapper.SysDeptMapper;
import com.cicadasmall.system.wrapper.DeptWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>
 * 机构部门 服务实现类
 * </p>
 *
 * @author westboy
 * @date 2019-07-21
 */
@Service
public class DeptServiceImpl extends BaseService<SysDeptMapper, DeptDO> implements IDeptService {

    @Override
    public List<DeptVO> findList(DeptQueryDTO deptQueryDTO) {
        LambdaQueryWrapper<DeptDO> lambdaQueryWrapper = getLambdaQueryWrapper().orderByAsc(DeptDO::getSortId);

        if (Fn.isNotEmpty(deptQueryDTO.getDeptName())) {
            lambdaQueryWrapper.like(DeptDO::getDeptName, deptQueryDTO.getDeptName());
        }

        if (Fn.isNotNull(deptQueryDTO.getParentId())) {
            lambdaQueryWrapper.eq(DeptDO::getParentId, deptQueryDTO.getParentId());
        }

        List<DeptDO> deptList = baseMapper.selectList(lambdaQueryWrapper);
        return DeptWrapper.newBuilder().listVO(deptList);
    }

    @Override
    public List<DeptDO> findByUserId(Serializable userId) {
        return baseMapper.selectByUserId(userId);
    }

    @Override
    public List<DeptVO> getTree() {
        List<DeptDO> deptList = baseMapper.selectList(getLambdaQueryWrapper().orderByAsc(DeptDO::getSortId));
        return DeptWrapper.newBuilder().treeVO(deptList);
    }

    private void checkAndUpdate(DeptDO dept) {

        DeptDO currentDept = getById(dept.getDeptId());

        if (Fn.isNull(currentDept)) {
            throw new ServiceException("参数错误！");
        }

        if (Fn.equal(dept.getParentId(), currentDept.getDeptId())) {
            throw new ServiceException("上级部门不能为当前部门！");
        }


        List<DeptDO> currentDeptChildList = findByParentId(currentDept.getDeptId());

        if (Fn.isNotNull(dept.getParentId()) && Fn.notEqual(Constant.PARENT_ID, dept.getParentId()) && Fn.notEqual(dept.getParentId(), currentDept.getParentId())) {

            DeptDO currentParentDept = getById(dept.getParentId());

            if (currentParentDept == null) {
                throw new ServiceException("上级部门不存在！");
            }

            if (Fn.isNotEmpty(currentDeptChildList)) {
                AtomicReference<Boolean> error = new AtomicReference<>(false);
                currentDeptChildList.parallelStream().forEach(e -> error.set(e.getDeptId().equals(currentParentDept.getDeptId())));
                if (error.get()) {
                    throw new ServiceException("上级部门选择有误！");
                }
            }

            currentParentDept.setHasChildren(true);
            updateById(currentParentDept);

        }

        //Jin 判断当前部门是否拥有下级部门
        dept.setHasChildren(Fn.isNotEmpty(currentDeptChildList));

        updateById(dept);

        DeptDO quondamParentDept = getById(currentDept.getParentId());
        if (Fn.isNotNull(quondamParentDept)) {
            List<DeptDO> parentDeptChildList = findByParentId(currentDept.getParentId());
            if (Fn.isEmpty(parentDeptChildList)) {
                quondamParentDept.setHasChildren(false);
                updateById(quondamParentDept);
            }
        }

    }

    private void checkAndSave(DeptDO dept) {
        DeptDO parentDept = null;

        //检查上级部门是否存在
        if (Fn.isNotNull(dept.getParentId()) && Fn.notEqual(Constant.PARENT_ID, dept.getParentId())) {
            parentDept = getById(dept.getParentId());
            if (parentDept == null) {
                throw new ServiceException("上级部门选择有误！");
            }
        } else {
            dept.setParentId(Constant.PARENT_ID);
        }

        save(dept);

        //更新上级部门
        if (Fn.isNotNull(parentDept)) {
            parentDept.setHasChildren(true);
            updateById(parentDept);
        }

    }

    @Override
    public List<DeptDO> findByParentId(Serializable parentId) {
        return baseMapper.selectList(getLambdaQueryWrapper().eq(DeptDO::getParentId, parentId));
    }

    @Transactional
    @Override
    public boolean deleteDept(Serializable deptId) {
        LambdaQueryWrapper<DeptDO> queryWrapper = getLambdaQueryWrapper().eq(DeptDO::getParentId, deptId);
        Integer count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new ServiceException("请先删除子部门后再操作！");
        }

        DeptDO dept = getById(deptId);

        if (Fn.isNull(dept)) {
            throw new ServiceException("部门不存在！");
        }

        removeById(deptId);

        if (Fn.isNotNull(dept.getParentId()) && Fn.notEqual(Constant.PARENT_ID, dept.getParentId())) {
            Integer childCount = baseMapper.selectCount(getLambdaQueryWrapper().eq(DeptDO::getParentId, dept.getParentId()));

            //更新上级菜单状态
            if (childCount <= 0) {
                DeptDO parentMenu = getById(dept.getParentId());
                parentMenu.setHasChildren(false);
                updateById(parentMenu);
            }

        }
        return true;
    }

    @Override
    public R save(DeptInputDTO deptInputDTO) {
        checkAndSave(deptInputDTO.convertToEntity());
        return R.ok("部门保存成功！");
    }

    @Override
    public R update(DeptUpdateDTO deptUpdateDTO) {
        checkAndUpdate(deptUpdateDTO.convertToEntity());
        return R.ok(true);
    }

    @Override
    public R findById(Serializable id) {
        DeptDO dept = baseMapper.selectById(id);
        if (Fn.isNull(dept)) {
            throw new ServiceException("部门不存在！");
        }
        return R.ok(DeptWrapper.newBuilder().entityVO(dept));
    }

    @Override
    public R deleteById(Serializable id) {
        return R.ok(deleteDept(id));
    }

}
